package rldungeon.help

import scalax.collection.GraphEdge.{NodeProduct, EdgeCopy, UnDiEdge}
import scalax.collection.GraphPredef.OuterEdge
import net.cyndeline.scalarlib.rldungeon.dgs.graph.{Room, DGSFunctionality}
import net.cyndeline.scalarlib.rlgraph.util.EdgeCopyFactory
import net.cyndeline.scalarlib.util.EdgeFactory


class CorridorEdge[N](nodes: Product, bottleneckStatus: Boolean, respondersLeft: Int, val responders: Vector[Int]) extends UnDiEdge[N](nodes)
  with EdgeCopy[CorridorEdge]
  with OuterEdge[N,CorridorEdge]
  with DGSFunctionality[N, CorridorEdge] {

  /**
   * A method that only has to report the status set by setBottleneckStatus().
   * @return True if this edge must be traversed when visiting every room on a map.
   */
  override def isBottleneck: Boolean = bottleneckStatus

  /**
   * Sets this edges bottleneck status.
   * @param status True if this edge must be traversed when visiting every room on a map, otherwise false.
   * @return A copy of the edge with its bottleneck status set.
   */
  override def setBottleneckStatus(status: Boolean): CorridorEdge[N] with OuterEdge[N, CorridorEdge] = CorridorEdge(this._1, this._2, status, respondersLeft)

  /**
   * Keeps track of how many additional responders that can be placed on an edge.If the edge is incapable of hosting
   * responders, this method should always return 0, as it is the only method used when examining responder capacity.
   * @return The amount of additional responders this edge can host.
   */
  override def remainingResponderCapacity: Int = respondersLeft

  def addResponders(responderCollection: Int*): CorridorEdge[N] with OuterEdge[N, CorridorEdge] = if (respondersLeft > 0) {
    CorridorEdge(this._1, this._2, bottleneckStatus, respondersLeft - 1, this.responders ++ responderCollection)
  } else {
    this
  }

  override def copy[NN](newNodes: Product) = new CorridorEdge[NN](newNodes, bottleneckStatus, respondersLeft, responders)

}

final class CorridorCopyFactory[V <: Room[V]] extends EdgeCopyFactory[V, CorridorEdge] {
  def copyEdge(edge: CorridorEdge[V], a: V, b: V): CorridorEdge[V] with OuterEdge[V, CorridorEdge] = CorridorEdge(a, b, edge.isBottleneck, edge.remainingResponderCapacity, edge.responders)
}

final class CorridorFactory[V <: Room[V]] extends EdgeFactory[V, CorridorEdge] {
  def produce(from: V, to: V): CorridorEdge[V] with OuterEdge[V, CorridorEdge] = CorridorEdge(from, to)
}

object CorridorEdge {
  def apply[V](from: V, to: V) = new CorridorEdge[V](NodeProduct(from, to), false, 1, Vector[Int]())
  def apply[V](from: V, to: V, respondersLeft: Int) = new CorridorEdge[V](NodeProduct(from, to), false, respondersLeft, Vector[Int]())
  def apply[V](from: V, to: V, bottleStatus: Boolean, respondersLeft: Int) = new CorridorEdge[V](NodeProduct(from, to), bottleStatus, respondersLeft, Vector[Int]())
  def apply[V](from: V, to: V, bottleStatus: Boolean, respondersLeft: Int, responders: Vector[Int]) = new CorridorEdge[V](NodeProduct(from, to), bottleStatus, respondersLeft, responders)
}
